#ifndef STATE_HPP
#define STATE_HPP
/**
 * @file   state.hpp
 * @author Kimmo Luoma <kimmo\@PHOTON3>
 * @date   Thu Sep 27 16:58:57 2012
 * 
 * @brief  Class for storing the state of the walker.
 * State space for walker is \f$ \mathcal{H}_C\otimes\mathcal{H}_V \f$,
 * where \f$ \mathcal{H}_C \f$ is \f$ d \f$-dimensional coin space, where
 * \f$ d \f$ is the degree of the graph, and where 
 * \f$ \mathcal{H}_V \f$ is \f$\vert V \vert\f$-dimensional 
 * position space, where \f$ V\f$ ist the set of vertices.
 * 
 * Key of the map matches the vertice and vector 
 * corresponds to the internal degrees of freedom e.g. edges.
 * 
 */


#include <map>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix_proxy.hpp>
#include <cmath>
#include <complex>
#include "shift.hpp"
#include "coin.hpp"
#include "RefBase.hpp"

using namespace boost::numeric::ublas;
namespace QuantumWalk{
  
  template<typename T> 
  class state: virtual public RefBase{
  private:
    std::map<int,vector<T> > data;
    int dimV;
    int dimD;
  public:
    /** 
     * Constructor
     * 
     */
    state(){};
    /** 
     * Destructor
     * 
     */
    //~state();
    /** 
     * copy constructor
     * 
     * @param psi 
     */
    state(const state& psi);
    /** 
     * Copy assingment
     * 
     * @param psi 
     * 
     * @return reference to state
     */
    state& operator=(const state& psi);
    /** 
     * Constructor
     * Each row of matrix \f$ m \f$ gives the internal state in the site v, eg.
     * $m_{i,v}$ is the amplitude of the \f$ i\f$ th internal state component
     * the state at site \f$ v \f$. 
     *
     * @param mat \f$ d \times \vert V \vert \f$ matrix
     */
    state(matrix<T> m);
    //void add_state(int i,vector<T> v);
    
    template<typename U> friend class shift;
    template<typename U> friend class coin;
    
    /** 
     * Action of the shift operator to the state \f$ \vert\psi\rangle \f$.
     * \f$ \vert\psi'\rangle=S\vert\psi\rangle \f$.
     * This function modifies the state without making extra copies e.g in place. 
     * 
     * @param S \f$ S \f$ shift operator.
     * 
     * @return \f$ \vert\psi\rangle \leftarrow S\vert\psi\rangle\f$.
     */
    state& operator*=(shift<T>& S);
    
    /** 
     * Action of the coin  operator to the state \f$ \vert\psi\rangle \f$.
     * \f$ \vert\psi'\rangle=C\vert\psi\rangle \f$.
     * This function makes extra copy.
     * 
     * @param C coin operator class 
     * 
     * @return \f$ \vert\psi\rangle \leftarrow C\vert\psi\rangle\f$.
     */
    state& operator*=(const coin<T>& C);
    
    /** 
     * Calculate probability distribution over the sites
     * 
     * 
     * @return vector<double> 
     */
    vector<double> prob_sites();
    
    /** 
     * Calculate probability distribution over internal states
     * 
     * 
     * @return vector<double>
     */
    vector<double> prob_internal();
    
    int no_vertices() const{
      return dimV;
    };
    int no_internal_deg() const {
      return dimD;
    };
    
    const T& operator()(int d,int v) const;

  };

  /** 
   * Action of the shift  operator to the state \f$ \vert\psi\rangle \f$.
   * \f$ \vert\psi'\rangle=S\vert\psi\rangle \f$.
   * 
   * @param S shift operator class
   * @param psi state class
   * 
   * @return \f$ \vert\psi'\rangle = S\vert\psi\rangle\f$.
   */
  
  template<typename T>
  state<T> operator*(shift<T>& S, state<T> psi){
    return psi *= S;
  };
  
  /** 
   * Action of the coin  operator to the state \f$ \vert\psi\rangle \f$.
   * \f$ \vert\psi'\rangle=C\vert\psi\rangle \f$.
   * 
   * @param C coin operator class
   * @param psi shift operator class
   * 
   * @return \f$ \vert\psi'\rangle = C\vert\psi\rangle\f$.
   */
  
  template<typename T>
  state<T> operator*(coin<T>& C, state<T> psi){
    return psi *= C;
  };
  
}
#endif
